package org.wms.minbearwcs.serivce.mission.processor.inbound;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
import org.wms.minbearwcs.dao.inbound.inf.InboundOrderDetailDao;
import org.wms.minbearwcs.dao.mission.inf.WcsMissionDao;
import org.wms.minbearwcs.entity.DTO.agv.task.AgvActionSource;
import org.wms.minbearwcs.entity.DTO.agv.task.AgvTaskSource;
import org.wms.minbearwcs.entity.DTO.agv.task.actionEnum.AgvAction;
import org.wms.minbearwcs.entity.DTO.transfer.Tuple;
import org.wms.minbearwcs.entity.PO.agv.missionEnum.AgvMissionType;
import org.wms.minbearwcs.entity.PO.wcs.inbound.InboundOrderDetail;
import org.wms.minbearwcs.entity.PO.wcs.mission.WcsMission;
import org.wms.minbearwcs.entity.PO.wcs.mission.status.InboundMissionFor5Or6FloorStatus;
import org.wms.minbearwcs.entity.PO.wcs.mission.type.MissionType;
import org.wms.minbearwcs.resource.WcsResource;
import org.wms.minbearwcs.serivce.agv.task.agvTask.AgvTaskDispatcher;
import org.wms.minbearwcs.serivce.mission.processor.MissionProcessor;
import org.wms.minbearwcs.serivce.mission.processor.MissionProcessorCommonUtil;
import org.wms.minbearwcs.serivce.mission.storageProcessor.locker.Floor5Or6.Storage5Or6FloorLocker;
import org.wms.minbearwcs.utils.IdWorker;

import java.time.LocalDateTime;

@Slf4j
@Component
@RequiredArgsConstructor
public class Inbound5Or6FloorMissionProcessor implements MissionProcessor {

    private final InboundOrderDetailDao inboundOrderDetailDao;
    private final AgvTaskDispatcher getPutTaskDispatcher;
    private final TransactionTemplate transactionTemplate;
    private final WcsMissionDao wcsMissionDao;
    private final WcsResource wcsResource;
    private final IdWorker idWorker;
    private final Storage5Or6FloorLocker storage5Or6FloorLocker;
    private final MissionProcessorCommonUtil commonUtil;

    private final Object lock = new Object();

    @Override
    public MissionType getMissionType() {
        return MissionType.INBOUND_5_OR_6_FLOOR;
    }

    @Override
    public void process(WcsMission mission) {
        InboundMissionFor5Or6FloorStatus missionStatus = (InboundMissionFor5Or6FloorStatus) mission.getEnumMissionStatus();

        switch (missionStatus) {
            case WAIT_FOR_DISPATCH_EXCHANGE_STORAGE:
                dispatchExchangeAgvTask(mission);
                break;
            case DISPATCHING_EXCHANGE_STORAGE:
                break;
            case PROCESSING_EXCHANGE_STORAGE:
                break;
            case WAIT_FOR_CHECK_SKU:
                break;
            case CHECKING_SKU:
                break;
            case WAIT_FOR_DISPATCH_REAL_STORAGE:
                dispatchRealStorageAgvTask(mission);
                break;
            case DISPATCHING_REAL_STORAGE:
                break;
            case PROCESSING_REAL_STORAGE:
                break;
            case FINISH:
                finishWcsMission(mission);
                break;
            case CANCEL:
                break;
        }


    }

    public InboundOrderDetail getOrderDetail(Integer detailId) {
        return inboundOrderDetailDao.selectById(detailId);
    }

    public boolean statusChange(Integer missionId, InboundMissionFor5Or6FloorStatus oldStatus, InboundMissionFor5Or6FloorStatus newStatus) {
        return Boolean.TRUE.equals(transactionTemplate.execute(status -> {
            try {
                if (oldStatus == wcsMissionDao.selectMissionStatusById(missionId)) {
                    synchronized (lock) {
                        if (oldStatus == wcsMissionDao.selectMissionStatusById(missionId)) {
                            wcsMissionDao.updateMissionStatusById(missionId, newStatus.name());
                            wcsMissionDao.updateStartTime(missionId,LocalDateTime.now());
                            return true;
                        }
                    }
                }
            } catch (Exception e) {
                log.error("wcs任务状态转换出错", e);
                status.setRollbackOnly();
            }
            return false;
        }));
    }


    // 交接区储位任务下发
    public void dispatchExchangeAgvTask(WcsMission missionInfo) {
        if (!statusChange(missionInfo.getId(),
                InboundMissionFor5Or6FloorStatus.WAIT_FOR_DISPATCH_EXCHANGE_STORAGE,
                InboundMissionFor5Or6FloorStatus.DISPATCHING_EXCHANGE_STORAGE
        )) return;

        InboundOrderDetail orderDetail = getOrderDetail(missionInfo.getAssociatedDetailId());
        wcsResource.getExecutor().execute(() -> transactionTemplate.executeWithoutResult(status -> {
            try {
                String agvTaskId = "Task_Agv_" + idWorker.nextId();
                AgvTaskSource agvTaskSource = new AgvTaskSource(agvTaskId, AgvMissionType.GET_REQLIFT_PUT,1, missionInfo.getMissionId(), missionInfo.getMissionType(),
                        InboundMissionFor5Or6FloorStatus.PROCESSING_EXCHANGE_STORAGE.name());
                agvTaskSource.addAction(new AgvActionSource(orderDetail.getStartPoint(), AgvAction.GET))
                        .addAction(new AgvActionSource(orderDetail.getLiftRequestPoint(),AgvAction.LIFT_REQUEST))
                        .addAction(new AgvActionSource(orderDetail.getExchangePoint(),AgvAction.PUT));

                if (getPutTaskDispatcher.dispatch(agvTaskSource)) {
                    wcsMissionDao.updateMissionStatusById(missionInfo.getId(), InboundMissionFor5Or6FloorStatus.PROCESSING_EXCHANGE_STORAGE.name());
                } else {
                    wcsMissionDao.updateMissionStatusById(missionInfo.getId(), InboundMissionFor5Or6FloorStatus.WAIT_FOR_DISPATCH_EXCHANGE_STORAGE.name());
                }
            } catch (Exception e) {
                log.error("wcs任务：{}，生成agv任务失败", missionInfo.getMissionId());
                status.setRollbackOnly();
                wcsMissionDao.updateMissionStatusById(missionInfo.getId(), InboundMissionFor5Or6FloorStatus.WAIT_FOR_DISPATCH_EXCHANGE_STORAGE.name());
            }
        }));
    }



    public void dispatchRealStorageAgvTask(WcsMission missionInfo) {
        if (!statusChange(missionInfo.getId(),
                InboundMissionFor5Or6FloorStatus.WAIT_FOR_DISPATCH_REAL_STORAGE,
                InboundMissionFor5Or6FloorStatus.DISPATCHING_REAL_STORAGE
        )) return;

        InboundOrderDetail orderDetail = getOrderDetail(missionInfo.getAssociatedDetailId());
        wcsResource.getExecutor().execute(() -> {
            Tuple<String> lockTuple = transactionTemplate.execute(status -> {
                try {
                    Tuple<String> temp = storage5Or6FloorLocker.lockStorage(orderDetail.getStoragePoint(), orderDetail.getPalletCode());
                    if (!temp.success) {
                        wcsMissionDao.updateMissionStatusById(missionInfo.getId(), InboundMissionFor5Or6FloorStatus.WAIT_FOR_DISPATCH_REAL_STORAGE.name());
                        return Tuple.tuple(null, false);
                    }
                    return temp;
                } catch (Exception e) {
                    log.error("5F/6F储位 {} 锁定失败", orderDetail.getStoragePoint(),e);
                    status.setRollbackOnly();
                    return Tuple.tuple(null, false);
                }
            });

            transactionTemplate.executeWithoutResult(status -> {
                try {
                    String agvTaskId = "Task_Agv_" + idWorker.nextId();
                    AgvTaskSource agvTaskSource = new AgvTaskSource(agvTaskId, AgvMissionType.GET_PASS_PUT,1, missionInfo.getMissionId(), missionInfo.getMissionType(),
                            InboundMissionFor5Or6FloorStatus.PROCESSING_REAL_STORAGE.name());
                    agvTaskSource.addAction(new AgvActionSource(orderDetail.getExchangePoint(), AgvAction.GET))
                            .addAction(new AgvActionSource(lockTuple.value,AgvAction.PASS))
                            .addAction(new AgvActionSource(orderDetail.getExchangePoint(),AgvAction.PUT));

                    if (getPutTaskDispatcher.dispatch(agvTaskSource)) {
                        wcsMissionDao.updateMissionStatusById(missionInfo.getId(), InboundMissionFor5Or6FloorStatus.PROCESSING_REAL_STORAGE.name());
                    } else {
                        wcsMissionDao.updateMissionStatusById(missionInfo.getId(), InboundMissionFor5Or6FloorStatus.WAIT_FOR_DISPATCH_REAL_STORAGE.name());
                    }
                } catch (Exception e) {
                    log.error("wcs任务：{}，生成agv任务失败", missionInfo.getMissionId());
                    status.setRollbackOnly();
                    wcsMissionDao.updateMissionStatusById(missionInfo.getId(), InboundMissionFor5Or6FloorStatus.WAIT_FOR_DISPATCH_REAL_STORAGE.name());
                }
            });
        });
    }


    public void finishWcsMission(WcsMission missionInfo) {
        transactionTemplate.executeWithoutResult(status->{
            try {
                missionInfo.setFinishTime(LocalDateTime.now());
                commonUtil.transformMissionHistory(missionInfo);
            }catch (Exception e){
                log.error("任务结束错误",e);
                status.setRollbackOnly();
            }
        });

    }

}
